package com.cat.recruit.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cat.recruit.bean.dto.AccessDTO;
import com.cat.recruit.bean.dto.AppointmentSlotDTO;
import com.cat.recruit.bean.dto.ListDTO;
import com.cat.recruit.bean.dto.UserDTO;
import com.cat.recruit.common.constant.*;
import com.cat.recruit.common.exception.BusinessExceptionEnum;
import com.cat.recruit.common.result.Result;
import com.cat.recruit.config.JwtUserDetails;
import com.cat.recruit.entity.*;
import com.cat.recruit.mapper.*;
import com.cat.recruit.service.AdminService;
import com.cat.recruit.service.CommonService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Time;
import java.text.ParseException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.cat.recruit.common.exception.BusinessException.bizException;

/**
 * @author cat
 *
 * 用于与管理后台相关的业务逻辑的实现类
 */
@Service
@Transactional(
        // 事务传播属性
        propagation = Propagation.REQUIRED,
        // 事务隔离属性
        isolation = Isolation.READ_COMMITTED,
        // 所有异常都回滚
        rollbackFor = Exception.class,
        // 10秒超时
        timeout = 10
)
public class AdminServiceImpl implements AdminService {

    @Autowired
    UserMapper userMapper;

    @Autowired
    PasswordEncoder passwordEncoder;

    @Autowired
    JwtUserDetailsServiceImpl jwtUserDetailsService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private AccessMapper accessMapper;
    @Autowired
    private AppointmentSlotMapper appointmentSlotMapper;
    @Autowired
    private StatesMapper statesMapper;
    @Autowired
    private UserAppointmentMapper userAppointmentMapper;
    @Autowired
    private CommonService commonService;
    @Autowired
    private ScoreCommentMapper scoreCommentMapper;

    /**
     * 管理员提交分数
     *
     * @param accessId 考核ID
     * @param score    分数
     * @param comment  评论
     * @return 提交结果
     */
    @Override
    public Result submitScore(Integer accessId, Integer score, String comment, JwtUserDetails jwtUserDetails) {
        if (accessMapper.selectById(accessId) == null){
            throw bizException(BusinessExceptionEnum.ASSESS_DATA_NOT_EXIST);
        }
        // 查询score_comment
        ScoreComment scoreComment = scoreCommentMapper.selectOne(
                new QueryWrapper<ScoreComment>()
                        .eq("access_id", accessId)
                        .eq("admin_id", jwtUserDetails.getId())
                        .eq("state",0)
        );
        if (scoreComment == null){
            scoreComment = ScoreComment.builder()
                    .accessId(accessId)
                    .adminId(jwtUserDetails.getId())
                    .adminName(jwtUserDetails.getUsername())
                    .score(score)
                    .comment(comment)
                    .state(0)
                    .build();
            scoreCommentMapper.insert(scoreComment);
        }else {
            scoreComment.setState(1);
            scoreCommentMapper.updateById(scoreComment);
            scoreComment = ScoreComment.builder()
                    .accessId(accessId)
                    .adminId(jwtUserDetails.getId())
                    .adminName(jwtUserDetails.getUsername())
                    .score(score)
                    .comment(comment)
                    .state(0)
                    .build();
            scoreCommentMapper.insert(scoreComment);
        }
        return Result.success();
    }

    /**
     * 管理员登录
     *
     * @param username 用户名
     * @param password 密码
     * @return 登录结果
     */
    @Override
    public Result login(String username, String password) {

        // 在数据库中查询用户信息
        User user = userMapper.selectByUsername(username);
        // 判断用户是否存在
        if (user == null) {
            throw bizException(BusinessExceptionEnum.USER_NOT_EXIST);
        }
        // 判断密码是否正确
        if (!passwordEncoder.matches(password,user.getPassword())){
            throw bizException(BusinessExceptionEnum.PASSWORD_ERROR);
        }
        // 生成token和refreshToken
        String token = jwtUserDetailsService.generateToken(user);
        String refreshToken = jwtUserDetailsService.generateRefreshToken(user);

        // 生成用户信息DTO
        UserDTO userDTO = new UserDTO(user);

        // 封装数据
        Map<String, Object> data = new HashMap<>();
        data.put("token", token);
        data.put("refreshToken", refreshToken);
        data.put("user", userDTO);

        return Result.success(data);
    }

    /**
     * 获取报名列表
     *
     * @param pageNum  页码
     * @param pageSize 每页数量
     * @return 报名列表
     */
    @Override
    //@Cacheable(value = "apply", key = "'applyList::' + #pageNum + '::' + #pageSize")
    public Result getApplyList(Integer pageNum, Integer pageSize,String status,String direction) {
        // 分页查询字段direction不为null用户
        // 创建分页对象
        IPage<User> page = new Page<>(pageNum, pageSize);
        // 创建查询条件
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNotNull("direction");
        // 执行分页查询
        IPage<User> applyListPage = userMapper.selectPage(page, queryWrapper);

        if (!status.isEmpty()){
            if (UserStatus.contains(status)){
                queryWrapper.eq("state", status);
            }else {
                throw bizException(BusinessExceptionEnum.USER_STATUS_NOT_EXIST);
            }
        }

        if (!direction.isEmpty()){
            if (Direction.isContains(direction)){
                queryWrapper.eq("direction", direction);
            }else {
                throw bizException(BusinessExceptionEnum.DIRECTION_NOT_EXIST);
            }
        }

        // 转换为DTO对象
        List<UserDTO> applyList = applyListPage.getRecords().stream()
                .map(UserDTO::new)
                .toList();

        // 封装数据
        ListDTO listDTO = ListDTO.builder()
                .total((int) applyListPage.getTotal())
                .totalPage((int) applyListPage.getPages())
                .pageNum((int) applyListPage.getCurrent())
                .currentSize(applyListPage.getRecords().size())
                .data(applyList)
                .build();
        return Result.success(listDTO);
    }

    /**
     * 添加预约时间段
     *
     * @param accessType      考核类型
     * @param direction       方向
     * @param interviewNumber 人数上限
     * @param appointmentDate 日期
     * @param startTime       开始时间
     * @param endTime         结束时间
     * @return 设置结果
     */
    //@CacheEvict(value = "appointment", key = "'allAppointment'")
    public Result addAppointmentTime(String accessType, String direction, Integer interviewNumber, String appointmentDate, String startTime, String endTime) {
        if (!AccessType.contains(accessType)){
            throw bizException(BusinessExceptionEnum.ACCESS_TYPE_NOT_EXIST);
        }
        // 查询方向是否存在
        if (!Direction.isContains(direction)){
            throw bizException(BusinessExceptionEnum.DIRECTION_NOT_EXIST);
        }
        try {
            // 保存考核时间段
            AppointmentSlot appointmentSlot = AppointmentSlot.builder()
                    .accessType(accessType)
                    .direction(direction)
                    // 将日期字符串转换为日期对象
                    .appointmentDate(new java.sql.Date(DateUtils.parseDate(appointmentDate, "yyyy-MM-dd").getTime()))
                    // 将时间字符串转换为时间对象
                    .startTime(new Time (DateUtils.parseDate(startTime, "HH:mm:ss").getTime()))
                    .endTime(new Time (DateUtils.parseDate(endTime, "HH:mm:ss").getTime()))
                    .capacity(interviewNumber)
                    .appointedCount(0)
                    .build();
            appointmentSlotMapper.insert(appointmentSlot);
        } catch (ParseException e) {
            // 参数格式错误异常
            throw bizException(BusinessExceptionEnum.PARAM_FORMAT_ERROR);
        }
        return Result.success();
    }

    /**
     * 管理员获取预约时间列表
     */
    @Override
    //@Cacheable(value = "appointment", key = "'allAppointment'")
    public Result getAppointmentTimeList() {
        List<AppointmentSlot> appointmentSlotList = appointmentSlotMapper.selectList(
                new QueryWrapper<AppointmentSlot>()
                        .eq("is_del",0)
        );
        //List<AppointmentSlot> appointmentSlotList = appointmentSlotMapper.selectList1();
        // 转换为DTO对象
        List<AppointmentSlotDTO> appointmentSlotDTOList = appointmentSlotList.stream()
                .map(AppointmentSlotDTO::new)
                .toList();
        return Result.success(appointmentSlotDTOList);
    }

    /**
     * 管理员获取用户信息
     *
     * @param userId 用户ID
     * @return 用户信息
     */
    //@Cacheable(value = "user", key = "'user::userId::' + #userId")
    @Override
    public Result getUserInfo(Integer userId) {
        // 查询用户信息
        User user = userMapper.selectById(userId);
        if (user == null){
            throw bizException(BusinessExceptionEnum.USER_NOT_EXIST);
        }
        // 转换为DTO对象
        UserDTO userDTO = new UserDTO(user);
        return Result.success(userDTO);
    }

    /**
     * 管理员设置招聘状态
     *
     * @param status 状态
     * @return 设置结果
     */
    @CachePut(value = "states", key = "'states::' + #status")
    @Override
    public Result setRecruitStatus(String status) {
        // 从数据库中查询状态
        States oldStatus = statesMapper.selectByKey(StateKey.RECRUIT_STATE);
        oldStatus.setValue(status);
        // 更新状态
        statesMapper.updateById(oldStatus);
        Map<String, Object> data = new HashMap<>();
        data.put("status", status);
        return Result.success(data);
    }

    @Override
    public Result getUsersByAppointmentTime(Integer appointmentSlotId) {
        // 查询预约时间段
        AppointmentSlot appointmentSlot = appointmentSlotMapper.selectOne(
                new QueryWrapper<AppointmentSlot>()
                        .eq("id", appointmentSlotId)
                        .eq("is_del", 0)
        );
        //AppointmentSlot appointmentSlot = appointmentSlotMapper.selectById(appointmentSlotId);
        if (appointmentSlot == null){
            throw bizException(BusinessExceptionEnum.APPOINTMENT_SLOT_NOT_EXIST);
        }
        // 查询预约时间段内的用户
        List<UserAppointment> userAppointmentList = userAppointmentMapper.selectList(new QueryWrapper<UserAppointment>()
                .eq("appointment_id", appointmentSlotId)
                .eq("is_del", 0)
        );
        List<UserDTO> userDTOList = userAppointmentList.stream()
                .map(userAppointment -> commonService.getUserDtoByUserId(userAppointment.getUserId()))
                .toList();
        return Result.success(userDTOList);
    }

    @Override
    public Result getScore(Integer userId) {
        // 查询用户考核信息
        List<Access> accessList = accessMapper.selectList(new QueryWrapper<Access>()
                .eq("user_id", userId)
                .orderByDesc("create_time")
        );
        // 转换为DTO对象
        List<AccessDTO> accessDTOList = accessList.stream()
                .map(access -> commonService.getAccessDto(access))
                .toList();
        return Result.success(accessDTOList);
    }

    //@CacheEvict(value = "appointmentSlot", key = "'appointmentSlotDto::id::'+#appointmentSlotId")
    @Override
    public Result deleteAppointmentSlot(Integer appointmentSlotId) {
        // 删除预约时间段
        if (appointmentSlotMapper.deleteById(appointmentSlotId) == 0){
            throw bizException(BusinessExceptionEnum.APPOINTMENT_SLOT_NOT_EXIST);
        }
        // 删除用户预约时间段关联表
        userAppointmentMapper.delete(
                new QueryWrapper<UserAppointment>()
                        .eq("appointment_id", appointmentSlotId)
        );
        return Result.success();
    }

    @Override
    public Result updateAppointmentSlot(Integer id, String accessType, String direction, String appointmentDate, String startTime, String endTime, Integer capacity) {
        // 查询预约时间段
        AppointmentSlot appointmentSlot = appointmentSlotMapper.selectById(id);
        if (appointmentSlot == null){
            throw bizException(BusinessExceptionEnum.APPOINTMENT_SLOT_NOT_EXIST);
        }
        // 更新预约时间段
        appointmentSlot.setAccessType(accessType);
        appointmentSlot.setDirection(direction);
        try {
            appointmentSlot.setAppointmentDate(new java.sql.Date(DateUtils.parseDate(appointmentDate, "yyyy-MM-dd").getTime()));
            appointmentSlot.setStartTime(new Time (DateUtils.parseDate(startTime, "HH:mm:ss").getTime()));
            appointmentSlot.setEndTime(new Time (DateUtils.parseDate(endTime, "HH:mm:ss").getTime()));
        } catch (ParseException e) {
            // 参数格式错误异常
            throw bizException(BusinessExceptionEnum.PARAM_FORMAT_ERROR);
        }
        appointmentSlot.setCapacity(capacity);
        appointmentSlotMapper.updateById(appointmentSlot);
        return Result.success(
                commonService.getAppointmentSlotDtoById(appointmentSlot.getId())
        );
    }

    @Override
    public Result updateUserStatus(Integer userId, String status) {
        // 查询用户信息
        User user = userMapper.selectById(userId);
        if (user == null){
            throw bizException(BusinessExceptionEnum.USER_NOT_EXIST);
        }
        // 查询状态是否存在
        if (!UserStatus.contains(status)){
            throw bizException(BusinessExceptionEnum.USER_STATUS_NOT_EXIST);
        }
        // 更新用户状态
        user.setState(status);
        userMapper.updateById(user);
        return Result.success();
    }

    @Override
    public Result generateAccess(String accessType) {
        if (!AccessType.contains(accessType)){
            throw bizException(BusinessExceptionEnum.ACCESS_TYPE_NOT_EXIST);
        }

        List<AppointmentSlot> appointmentSlotList = appointmentSlotMapper.selectList(new QueryWrapper<AppointmentSlot>()
                .eq("access_type", accessType)
                .eq("state", 0)
                .eq("is_del", 0)
        );
        Integer count = 0;
        // 查询所有预约时间段内的用户
        for (AppointmentSlot appointmentSlot : appointmentSlotList){
            List<UserAppointment> userAppointmentList = userAppointmentMapper.selectList(new QueryWrapper<UserAppointment>()
                    .eq("appointment_id", appointmentSlot.getId())
            );
            for (UserAppointment userAppointment : userAppointmentList){
                // 查询用户信息
                User user = commonService.getUserByUserId(userAppointment.getUserId());
                // 生成考核信息
                Access access = Access.builder()
                        .userId(user.getUserId())
                        .accessType(accessType)
                        .direction(user.getDirection())
                        .appointmentSlotId(appointmentSlot.getId())
                        .state(0)
                        .build();
                accessMapper.insert(access);
                count++;
            }
            // 修改预约时间段状态
            appointmentSlot.setState(1);
            appointmentSlotMapper.updateById(appointmentSlot);
        }
        // 修改所有已预约的用户的状态
        userMapper.update(null, new UpdateWrapper<User>()
                .set("state", UserStatus.Accessing(accessType))
                .eq("state", UserStatus.appointedAccess(accessType))
        );

        return Result.success(Map.of("count", count));
    }
}
